<?php

namespace App\Trip\Hotel\Providers\Meituan;

use Carbon\Carbon;
use Exception;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Support\Facades\Log;

class Hotel
{
    public bool   $test     = true;
    public string $base_url = 'https://fenxiao.meituan.com/opdtor/api';
    public string $v1_uri   = "";
    public string $v2_uri   = "/v2";
    public string  $version1 = '1.0';
    public string  $version2 = '2.0';
    private Client $client;
    private int    $partnerId = 27054;
    private string $accesskey = "";
    private string $secretkey = "";

    public function __construct()
    {
        $this->client = new Client();
    }

    /**
     * @throws GuzzleException
     */
    public function hotelPoiList(int $maxId = 0, int $pageSize = 1): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.poi.list', $this->version1);
        $param['data']      = json_encode([
                'maxId'    => $maxId,
                'pageSize' => $pageSize,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
//		dd($this->buildParam($param), $param,json_encode($param));
        $response = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);

        return $response->getBody()->getContents();

    }

    public function hotelPoiInfoChangeCallback(array $changeInfos
                                               = [
        'hotelId'     => 52786813,
        'changeTypes' => [1, 2, 3, 4,],
    ], string                                        $changeTime = ''): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.poi.info.change.callback', $this->version1);
        $param['data']      = json_encode([
                'changeInfos' => $changeInfos,
                'changeTime'  => Carbon::now()->toDateTimeString(),
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
//		dd($this->buildParam($param), $param,json_encode($param));
        $response = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);

        return $response->getBody()->getContents();

    }

    public function hotelProductInfoChangeCallback(int $maxId = 0, int $pageSize = 1): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.poi.list', $this->version1);
        $param['data']      = json_encode([
                'maxId'    => $maxId,
                'pageSize' => $pageSize,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
//		dd($this->buildParam($param), $param,json_encode($param));
        $response = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);

        return $response->getBody()->getContents();

    }

    public function hotelContent(array $hotelIds = [52786813], array $include
    = [
        "HotelContent.baseInfo",
        "HotelContent.detailInfo",
        "HotelContent.notices",
        "HotelContent.policy",
        "HotelContent.facilities",
        "HotelContent.images",
        "HotelContent.roomBaseInfos",
    ]): string
    {
        $url                = $this->buildUri($this->version2);
        $param              = $this->getCommonParam('hotel.content', $this->version2);
        $param['data']      = json_encode([
                'hotelIds' => $hotelIds,
                'include'  => $include,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    public function hotelRealRoomContent(int $hotelId = 52786813, $realRoomIds = [2408491, 10761789]): string
    {
        $url                = $this->buildUri($this->version2);
        $param              = $this->getCommonParam('hotel.realroom.content', $this->version2);
        $param['data']      = json_encode([
                'hotelId'     => $hotelId,
                'realRoomIds' => $realRoomIds,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    public function hotelGoodsRp(
        array  $hotelIds = [52786813],
        string $checkinDate = "2023-03-07",
        string $checkoutDate = "2023-03-08",
        int    $goodsType = 1,
        array  $goodsIds = [24178517, 24180111],
    ): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.goods.rp', $this->version1);
        $param['data']      = json_encode([
                'hotelIds'     => $hotelIds,
                'checkinDate'  => $checkinDate,
                'checkoutDate' => $checkoutDate,
                'goodsType'    => $goodsType,
                'goodsIds'     => $goodsIds,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }




    public function hotelGoodsPrice(
        array  $hotelIds = [52786813],
        string $startDate = "2022-07-05",
        string $endDate = "2022-07-06",
        int    $priceType = 1, // 1 || 2 低价日历
        array  $goodsIds = [24178517, 24180111],
    ): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.goods.price', $this->version1);
        $param['data']      = json_encode([
                'hotelIds'  => $hotelIds,
                'startDate' => $startDate,
                'endDate'   => $endDate,
                'priceType' => $priceType,
                'goodsIds'  => $goodsIds,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    public function hotelGoodsStatus(
        int    $hotelId = 52786813,
        string $checkinDate = "2022-07-05",
        string $checkoutDate = "2022-07-06",
        int    $goodsType = 1,
    ): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.goods.status', $this->version1);
        $param['data']      = json_encode([
                'hotelId'      => $hotelId,
                'checkinDate'  => $checkinDate,
                'checkoutDate' => $checkoutDate,
                'goodsType'    => $goodsType,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    public function hotelOrderCheck(
        int    $hotelId = 52786813,
        int    $goodsId = 24180111,
        string $checkinDate = "2022-07-05",
        string $checkoutDate = "2022-07-06",
        int    $roomNum = 1,
        int    $totalPrice = 8000,
    ): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.order.check', $this->version1);
        $param['data']      = json_encode([
                'hotelId'      => $hotelId,
                'goodsId'      => $goodsId,
                'checkinDate'  => $checkinDate,
                'checkoutDate' => $checkoutDate,
                'roomNum'      => $roomNum,
                'totalPrice'   => $totalPrice,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    public function hotelOrderBooking(
        int    $hotelId = 52786813,
        int    $goodsId = 24178517,
        string $arriveDate = "2022-07-05 21:30:00",
        string $checkinDate = "2022-07-05",
        string $checkoutDate = "2022-07-06",
        int    $roomNum = 1,
        int    $totalPrice = 2700,
    ): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.order.booking', $this->version1);
        $param['data']      = json_encode([
                'hotelId'            => $hotelId,
                'goodsId'            => $goodsId,
                'arriveDate'         => $arriveDate,
                'checkinDate'        => $checkinDate,
                'checkoutDate'       => $checkoutDate,
                'roomNum'            => $roomNum,
                'totalPrice'         => $totalPrice,
                'settlePrice'        => $totalPrice - 135,
                'distributorOrderId' => Carbon::now()->timestamp,
                'personNames'        => '马豆',
                'contactName'        => '马豆',
                'contactPhone'       => '18599165206',
                //											  'personIdentities'   => '654121199111112311',
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        Log::info(json_encode($param, JSON_UNESCAPED_UNICODE));
        $response = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        $res      = $response->getBody()->getContents();
        Log::info($res);
        return $res;
    }

    public function hotelOrderQuery($queryParams
                                    = [
        [
            "distributorOrderId" => "1656991449",
            "mtOrderId"          => 4890920417654721144,
        ],
    ]): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.order.query', $this->version1);
        $param['data']      = json_encode([
                'queryParams' => $queryParams,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
//		dd($param);
        $response = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    public function hotelOrderReminder($mtOrderId = 4890920415977190606): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.order.reminder', $this->version1);
        $param['data']      = json_encode([
                'mtOrderId' => $mtOrderId,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }


    public function hotelOrderCancel(
        $mtOrderId = 4890920415977190606,
        string $distributorOrderId = "1656991029",
        string $cancelReason = "计划有变",
    ): string
    {
        $url                = $this->buildUri($this->version1);
        $param              = $this->getCommonParam('hotel.order.cancel', $this->version1);
        $param['data']      = json_encode([
                "distributorOrderId" => $distributorOrderId,
                "mtOrderId"          => $mtOrderId,
                "cancelReason"       => $cancelReason,
                "cancelCheck"        => 0,
            ]
            ,                             JSON_UNESCAPED_UNICODE);
        $param['signature'] = $this->signature($this->buildParam($param));
        $response           = $this->client->post($url, [
            'headers' => [
                'Content-Type' => 'application/json;charset=utf-8',
                'Accept'       => 'application/json;',
            ],
            'json'    => $param,
        ]);
        return $response->getBody()->getContents();
    }

    private function buildParam(array $arr): string
    {
        ksort($arr);
        // or http_build_query
        $arr = collect($arr)->map(fn($v, $k) => $k."=".$v)->toArray();
        return implode('&', $arr);
    }


    private function getCommonParam($method, $version): array
    {
        $param = [
            "method"    => $method,
            "version"   => $version,
            "timestamp" => Carbon::now()->timestamp,
            "nonce"     => random_int(10000,99999),
            "partnerId" => $this->partnerId,
            "accesskey" => $this->accesskey,
        ];
        if ($this->test) {
            $param["test"] = "test";
        }
        if ($version == $this->version2) {
            $param["customerSessionId"] = "18599165206";
            $param["language"]          = "zh_CN";
        }
        return $param;
    }

    private function buildUri(string $version): string
    {
        if ($version == $this->version1) {
            return $this->base_url . $this->v1_uri;
        } elseif ($version == $this->version2) {
            return $this->base_url . $this->v2_uri;
        } else {
            throw new Exception("Invalid version {$version}");
        }

    }

    private function signature(string $plainText): string
    {
        return base64_encode(hash_hmac('sha1', $plainText, $this->secretkey, true));
    }
}
